/**
 * @author  Thomas Lehmann
 * @file    Keywords.js
 *
 * Copyright (c) 2013 Thomas Lehmann
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
 * documentation files (the "Software"), to deal in the Software without restriction, including without limitation
 * the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
 * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all copies
 * or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
 * DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 */
var log;
var Class;
var Factory;

if (typeof require == 'function') {
    var ClassTools = require("./ClassTools.js");
    log         = ClassTools.log;
    Class       = ClassTools.Class;
    Factory     = ClassTools.Factory;
}

var DefaultKeywords = Class({
    initialize: function() {
        // http://en.cppreference.com/w/cpp/keyword
        this.data = [ 'bool', 'break', 'case', 'catch', 'char', 'class', 'const',
                      'const_cast', 'continue', 'default', 'defined', 'delete', 'double',
                      'dynamic_cast', 'else', 'endif', 'enum', 'explicit', 'extern',
                      'false', 'float', 'for', 'friend', 'if', 'ifdef', 'include',
                      'inline', 'int', 'long', 'mutable', 'namespace', 'new', 'operator',
                      'private', 'protected', 'public', 'reinterpret_cast', 'return',
                      'short', 'signed', 'sizeof', 'static', 'static_cast', 'struct',
                      'switch', 'template', 'this', 'throw', 'true', 'try', 'typedef',
                      'typeid', 'typename', 'union', 'unsigned', 'using', 'virtual', 'void' ];
    },

    isKeyword: function(token) {
        return this.data.indexOf(token) >= 0;
    },

    isCaseSensitive: function() {
        return true;
    }
});

var PascalKeywords = Class({
    initialize: function() {
        this.data = [ 'program', 'type', 'begin', 'end', 'break', 'for', 'downto',
                      'constructor', 'destructor', 'continue', 'and', 'or',
                      'array', 'case', 'const', 'do', 'div', 'else', 'function',
                      'false', 'true', 'if', 'mod', 'nil', 'of', 'procedure',
                      'repeat', 'set', 'shl', 'shr', 'string', 'then', 'to',
                      'type', 'unit', 'until', 'uses', 'var', 'while', 'with',
                      'xor', 'integer', 'longint', 'length', 'object', 'private',
                      'public', 'setlength', 'copy', 'strtoint' ];
    },

    isKeyword: function(token) {
        return this.data.indexOf(token.toLowerCase()) >= 0;
    },

    isCaseSensitive: function() {
        return false;
    }
});

var PythonKeywords = Class({
    initialize: function() {
        // http://en.wikipedia.org/wiki/Python_syntax_and_semantics
        this.data = [ 'False', 'None', 'True', 'and', 'as', 'assert', 'break', 'class',
                      'continue', 'def', 'del', 'elif', 'else', 'except', 'exec',
                      'finally', 'for', 'from', 'global', 'if', 'import', 'in', 'int',
                      'is', 'lambda', 'len', 'list', 'map', 'not', 'open', 'or', 'pass',
                      'print', 'raise', 'range', 'return', 'reversed', 'self', 'set',
                      'sorted', 'tuple'];
    },

    isKeyword: function(token) {
        return this.data.indexOf(token) >= 0;
    },

    isCaseSensitive: function() {
        return true;
    }
});

var JavaScriptKeywords = Class({
    initialize: function() {
        // http://en.wikibooks.org/wiki/JavaScript/Reserved_Words
        this.data = [ 'Array', 'break', 'case', 'catch', 'continue', 'default', 'delete',
                      'do', 'else', 'for', 'function', 'if', 'in', 'instanceof',
                      'new', 'switch', 'this', 'try', 'typeof', 'var', 'void', 'with'
                    ];
    },

    isKeyword: function(token) {
        return this.data.indexOf(token) >= 0;
    },

    isCaseSensitive: function() {
        return true;
    }
});

var JavaKeywords = Class({
    initialize: function() {
        // http://docs.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html
        this.data = [ 'abstract', 'assert', 'boolean', 'break', 'catch', 'char', 'class',
                      'continue', 'default', 'double', 'else', 'enum', 'extends',
                      'final', 'finally', 'float', 'for', 'if', 'implements', 'import',
                      'instanceof', 'int', 'interface', 'long', 'new', 'package',
                      'private', 'protected', 'public', 'return', 'short', 'static',
                      'super', 'switch', 'synchronized', 'this', 'throw', 'throws'
                    ];
    },

    isKeyword: function(token) {
        return this.data.indexOf(token) >= 0;
    },

    isCaseSensitive: function() {
        return true;
    }
});

var PHPKeywords = Class({
    initialize: function() {

        this.data = [ 'abstract', 'and', 'array', 'Array', 'as', 'break', 'case', 'catch',
                      'class', 'clone', 'const', 'continue', 'declare', 'default', 'define',
                      'do', 'echo', 'else', 'elseif', 'enddeclare', 'endfor', 'endforeach',
                      'endif', 'endswitch', 'endwhile', 'extends', 'final', 'for',
                      'foreach', 'function', 'global', 'if', 'implements', 'instanceof',
                      'interface', 'isset', 'list', 'namespace', 'new', 'or', 'print',
                      'private', 'protected', 'public', 'require', 'require_once',
                      'return', 'static', 'switch', 'this', 'throw', 'try', 'use', 'var'
                    ];
    },

    isKeyword: function(token) {
        return this.data.indexOf(token) >= 0;
    },

    isCaseSensitive: function() {
        return true;
    }
});

var BasicKeywords = Class({
    initialize: function() {

        this.data = [ 'abs', 'as', 'asc', 'asin', 'assert', 'atan2', 'byref', 'byval',
                      'call', 'callocate', 'case', 'cast', 'chr', 'constructor',
                      'continue', 'declare', 'dim', 'double', 'else', 'end', 'for', 'function',
                      'if', 'integer', 'next', 'print', 'private', 'ptr', 'reallocate',
                      'return', 'sizeof', 'str', 'sub', 'then', 'this', 'to', 'type'
                    ];
    },

    isKeyword: function(token) {
        return this.data.indexOf(token) >= 0;
    },

    isCaseSensitive: function() {
        return false;
    }
});

var RubyKeywords = Class({
    initialize: function() {

        this.data = ['alias', 'and', 'begin', 'break', 'case', 'class', 'def', 'defined',
                     'do', 'else', 'else', 'elsif', 'end', 'ensure', 'false', 'for',
                     'if', 'in', 'module', 'next', 'nil', 'not', 'or', 'redo', 'rescue',
                     'retry', 'return', 'self', 'super', 'then', 'true', 'undef'
                    ];
    },

    isKeyword: function(token) {
        return this.data.indexOf(token) >= 0;
    },

    isCaseSensitive: function() {
        return true;
    }
});

var PerlKeywords = Class({
    initialize: function() {

        this.data = ['and', 'bless', 'break', 'chop', 'chr', 'close', 'cmp', 'continue',
                      'die', 'do', 'dump', 'each', 'else', 'else', 'elsif', 'eq',
                      'eq', 'exp', 'for', 'foreach', 'ge', 'glob', 'grep', 'if',
                      'int', 'le', 'lt', 'my', 'ne', 'next', 'package', 'printf',
                      'push', 'qw', 'return', 'scalar', 'shift', 'sub', 'until', 'use'
                    ];
    },

    isKeyword: function(token) {
        return this.data.indexOf(token) >= 0;
    },

    isCaseSensitive: function() {
        return true;
    }
});

var GroovyKeywords = Class({
    initialize: function() {
        // http://docs.oracle.com/javase/tutorial/java/nutsandbolts/_keywords.html
        this.data = [ 'abstract', 'assert', 'boolean', 'break', 'catch', 'char', 'class',
                      'continue', 'default', 'double', 'else', 'enum', 'extends',
                      'final', 'finally', 'float', 'for', 'if', 'implements', 'import',
                      'instanceof', 'int', 'interface', 'long', 'new', 'package',
                      'private', 'protected', 'public', 'return', 'short', 'static',
                      'super', 'switch', 'synchronized', 'this', 'throw', 'throws',
                      'any', 'as', 'def', 'in', 'width'
                    ];
    },

    isKeyword: function(token) {
        return this.data.indexOf(token) >= 0;
    },

    isCaseSensitive: function() {
        return true;
    }
});

var CSharpKeywords = Class({
    initialize: function() {
        // http://msdn.microsoft.com/en-us/library/x53a06bb%28v=vs.71%29.aspx
        this.data = [ 'abstract', 'as', 'base', 'bool', 'break', 'byte', 'case',
                      'catch', 'char', 'checked', 'class', 'const', 'continue', 'decimal',
                      'default', 'delegate', 'do', 'double', 'else', 'enum', 'event',
                      'explicit', 'extern', 'false', 'finally', 'fixed', 'float',
                      'for', 'foreach', 'goto', 'if', 'implicit', 'in', 'int', 'interface',
                      'internal', 'is', 'lock', 'long', 'namespace', 'new', 'null',
                      'object', 'operator', 'out', 'override', 'params', 'private',
                      'protected', 'public', 'readonly', 'ref', 'return', 'sbyte',
                      'sealed', 'short', 'sizeof', 'stackalloc', 'static', 'string',
                      'struct', 'switch', 'this', 'throw', 'true', 'try', 'typeof',
                      'uint', 'ulong', 'unchecked', 'unsafe', 'ushort', 'using'
                    ];
    },

    isKeyword: function(token) {
        return this.data.indexOf(token) >= 0;
    },

    isCaseSensitive: function() {
        return true;
    }
});


var DKeywords = Class({
    initialize: function() {
        // http://dlang.org/lex.html#Keyword
        this.data = [ 'abstract', 'alias', 'align', 'asm', 'assert', 'auto', 'body',
                      'bool', 'break', 'byte', 'case', 'cast', 'catch', 'cdouble',
                      'cent', 'cfloat', 'char', 'class', 'const', 'continue', 'creal',
                      'dchar', 'debug', 'default', 'delegate', 'deprecated', 'do',
                      'double', 'else', 'enum', 'export', 'extern', 'false', 'final',
                      'finally', 'float', 'for', 'foreach', 'foreach_reverse', 'function',
                      'goto', 'idouble', 'if', 'ifloat', 'immutable', 'import', 'in',
                      'inout', 'int', 'interface', 'invariant', 'ireal', 'is', 'lazy',
                      'long', 'macro', 'mixin', 'module', 'new', 'nothrow', 'null',
                      'out', 'override', 'package', 'pragma', 'private', 'protected',
                      'public', 'pure', 'real', 'ref', 'return', 'scope', 'shared',
                      'short', 'static', 'struct', 'super', 'switch', 'synchronized',
                      'template', 'this', 'throw', 'true', 'try', 'typeid', 'typeof',
                      'ubyte', 'ucent', 'uint', 'ulong', 'union', 'unittest', 'ushort', 'void'
                    ];
    },

    isKeyword: function(token) {
        return this.data.indexOf(token) >= 0;
    },

    isCaseSensitive: function() {
        return true;
    }
});


var ScalaKeywords = Class({
    initialize: function() {
        // http://www.tutorialspoint.com/scala/scala_basic_syntax.htm
        this.data = [ 'abstract', 'case', 'catch', 'class', 'def', 'do', 'else', 'extends',
                      'false', 'final', 'finally', 'for', 'forSome', 'if', 'implicit',
                      'import', 'lazy', 'match', 'new', 'null', 'object', 'override',
                      'package', 'private', 'protected', 'return', 'sealed', 'super', 'this',
                      'throw', 'trait', 'try', 'true', 'type', 'val', 'var', 'while', 'with',
                      'yield'
                    ];
    },

    isKeyword: function(token) {
        return this.data.indexOf(token) >= 0;
    },

    isCaseSensitive: function() {
        return true;
    }
});

var BatchKeywords = Class({
    initialize: function() {
        // http://tldp.org/LDP/abs/html/dosbatch.html
        this.data = [ 'for', 'if', 'exists', 'goto', 'set', 'echo',
                      'in', 'not', 'EOF', 'do', 'call', 'exist', 'nul',
                      'pause', 'choice', 'shift', 'errorlevel', 'off',
                      'command', 'con', 'prn', 'lpt1', 'com1', 'exit',

                      'cd', 'copy', 'mkdir', 'find', 'move', 'findstr',
                      'cls', 'del', 'dir', 'more', 'rename', 'ren',
                      'sort', 'type', 'time', 'path'
                    ];
    },

    isKeyword: function(token) {
        return this.data.indexOf(token) >= 0;
    },

    isCaseSensitive: function() {
        return false;
    }
});

var KeywordFactory = new Factory();
KeywordFactory.register("default"    , DefaultKeywords);
KeywordFactory.register("c++"        , DefaultKeywords);
KeywordFactory.register("pascal"     , PascalKeywords);
KeywordFactory.register("python"     , PythonKeywords);
KeywordFactory.register("javascript" , JavaScriptKeywords);
KeywordFactory.register("java"       , JavaKeywords);
KeywordFactory.register("php"        , PHPKeywords);
KeywordFactory.register("basic"      , BasicKeywords);
KeywordFactory.register("ruby"       , RubyKeywords);
KeywordFactory.register("perl"       , PerlKeywords);
KeywordFactory.register("groovy"     , GroovyKeywords);
KeywordFactory.register("c#"         , CSharpKeywords);
KeywordFactory.register("d"          , DKeywords);
KeywordFactory.register("scala"      , ScalaKeywords);
KeywordFactory.register("batch"      , BatchKeywords);

if (typeof(exports) != 'undefined') {
    exports.KeywordFactory = KeywordFactory;
}

